/*
 * Feature.java
 *
 * Created on July 27, 2006, 11:46 AM
 *
 */

package galronnlp.perceptron;

import galronnlp.util.Symbol;

/**
 * A feature is a 2-tuple, mapping a feature type to a <code>Symbol</code>. There
 * are fourteen feature types defined in the Collins & Roark paper, and all are
 * implemented here.
 *
 * @author Daniel A. Galron
 */
public class Feature {
    
    public static int L00 =  0;
    public static int L10 =  1;
    public static int LKP =  2;
    public static int L01 =  3;
    public static int L02 =  4;
    public static int L03 =  5;
    public static int L20 =  6;
    public static int L11 =  7;
    public static int L30 =  8;
    public static int L21 =  9;
    public static int CL  = 10;
    public static int LK  = 11;
    public static int CCP = 12;
    public static int CC  = 13;
    
    private int type;
    private Symbol sym;
    
    /** Creates a new instance of Feature 
     *
     * @param t The feature type
     * @param s The Symbol mapped to the type
     */
    public Feature(int t, Symbol s) {
        type = t;
        sym = s;
    }
    
    /**
     * Creates a new instance of Feature
     *
     * @param t A String marking the feature type
     * @param s The Symbol mapped ot the type
     */
    public Feature(String t, Symbol s) {
        if(t.equalsIgnoreCase("L00")) {
            type = L00;
            sym = s;
        } else if(t.equalsIgnoreCase("L10")) {
            type = L10;
            sym = s;
        } else if(t.equalsIgnoreCase("LKP")) {
            type = LKP;
            sym = s;
        } else if(t.equalsIgnoreCase("L01")) {
            type = L01;
            sym = s;
        } else if(t.equalsIgnoreCase("L02")) {
            type = L02;
            sym = s;
        } else if(t.equalsIgnoreCase("L03")) {
            type = L03;
            sym = s;
        } else if(t.equalsIgnoreCase("L20")) {
            type = L20;
            sym = s;
        } else if(t.equalsIgnoreCase("L11")) {
            type = L11;
            sym = s;
        } else if(t.equalsIgnoreCase("L30")) {
            type = L30;
            sym = s;
        } else if(t.equalsIgnoreCase("L21")) {
            type = L21;
            sym = s;
        } else if(t.equalsIgnoreCase("CL")) {
            type = CL;
            sym = s;
        } else if(t.equalsIgnoreCase("LK")) {
            type = LK;
            sym = s;
        } else if(t.equalsIgnoreCase("CCP")) {
            type = CCP;
            sym = s;
        } else if(t.equalsIgnoreCase("CC")) {
            type = CC;
            sym = s;
        } else {
            System.err.println("unknown feature type " + t);
        }
    }
    
    public int type() {
        return type;
    }
    
    public Symbol node() {
        return sym;
    }
    
    public boolean equals(Object obj) {
        Feature other = (Feature)obj;
        return this.type == other.type && this.sym.equals(other.sym);
    }
    
    public String getXMLRep() {
        if(sym.toString().equals("&"))
            return "<feature type=\"" + typeString() + "\" label=\"&amp;\" ";
        else
            return "<feature type=\"" + typeString() + "\" label=\"" + sym + "\" ";
    }
    
    /**
     * @return the String representation of the feature type
     */
    public String typeString() {
        if(this.type == L00)
            return "L00";
        else if(this.type == L10)
            return "L10";
        else if(this.type == LKP)
            return "LKP";
        else if(this.type == L01)
            return "L01";
        else if(this.type == L02)
            return "L02";
        else if(this.type == L03)
            return "L03";
        else if(this.type == L20)
            return "L20";
        else if(this.type == L11)
            return "L11";
        else if(this.type == L30)
            return "L30";
        else if(this.type == L21)
            return "L21";
        else if(this.type == CL)
            return "CL";
        else if(this.type == LK)
            return "LK";
        else if(this.type == CCP)
            return "CCP";
        else if(this.type == CC)
            return "CC";
        else {
            System.err.println(this.type);
            return "";
        }
    }
    
    public String toString() {
        return "<" + typeString() + ", " + sym + ">";
    }
    
    /** 
     * The hash code of a feature is defined to be the product of the integer
     * representation of the type of feature and the hash code (integer representation)
     * of the symbol mapped to the type.
     */
    public int hashCode() {
        return this.type * this.sym.hashCode();
    }
    
}
